﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml.Linq;

using ZetaPrints.ZetaClient.Data;
using ZetaPrints.ZetaClient.Data.Repository.Linq;
using ZetaPrints.ZetaClient.Shared;
using ZetaPrints.ZetaClient.Business.ThreadSubSytem;

namespace ZetaPrints.ZetaClient.Business
{
    /// <summary>
    /// This is the site entry it will take care of everything relating to a 
    /// site entry.
    /// </summary>
    [DebuggerDisplay("{SiteEntry.SiteName},{Selected}")]
    public class SiteManager:BaseManager
    {
        #region private attribute
        /// <summary>
        /// This is the Guid that we should be using for the 
        /// thread manager
        /// </summary>
        private Guid OrderIdGuid
        {
            get
            {
                return new Guid(SiteEntry.SiteId, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
            }
        }
        #endregion


        #region public properties
        /// <summary>
        /// If this is set to true this site is selected 
        /// and should return request do to it.
        /// </summary>
        public bool Selected { get; set; }
        /// <summary>
        /// List of orders that this site got
        /// </summary>
        public List<OrderManager> OrderManagerList { get; set; }
        /// <summary>
        /// Gets or sets the order latest date time
        /// </summary>
        public DateTime LatestOrderDateTime
        {
            get
            {
                return _dataRepositoryManager.FetchLastOrderHeaderDateTime(SiteEntry.SiteId);
            }
        }
        public override bool AreThreadsAlive
        {
            get
            {
                bool areThreadsAlive = ThreadManager.AreThreadsAlive;

                /// look at the sub items
                if (!areThreadsAlive)
                {
                    foreach (OrderManager orderManager in OrderManagerList)
                    {
                        if (orderManager.AreThreadsAlive)
                        {
                            areThreadsAlive = true;
                            break;
                        }
                    }
                }

                return areThreadsAlive;
            }
        }
        #endregion


        #region constructors
        /// <summary>
        /// Initialize and start the web engine syste
        /// </summary>
        /// <param name="siteEntry"></param>
        public SiteManager(Site siteEntry):base(siteEntry)
        {
            Initialize();
        }
        /// <summary>
        /// Initialize and start the web engine using only the siteId
        /// </summary>
        /// <param name="siteId"></param>
        /// <returns></returns>
        public SiteManager(int siteId)
        {
            SiteEntry = _dataRepositoryManager.FetchSite(siteId);
            Initialize();
        }
        /// <summary>
        /// Initialize and start the web engine using only the name
        /// </summary>
        /// <param name="siteId"></param>
        /// <returns></returns>
        public SiteManager(string siteName)
        {
            SiteEntry = _dataRepositoryManager.FetchSite(siteName);
            Initialize();
        }
        #endregion


        #region private methods
        #region initialize
        /// <summary>
        /// Initializes anything that this site might need
        /// </summary>
        private void Initialize()
        {
            if (SiteEntry == null)
            {
                throw new ArgumentException("Internal error: The site information sent in to SiteManager is not valid");
            }

            /// get the web access ready
            _webAction = new WebAction(SiteEntry.SiteName, SiteEntry.ApiKey);

            /// get the messanger up and running
            _webAction.OnEventMessenger += new EventHandler<EventMessenger>(base_OnEventMessenger);

            /// we leave them empty for right now
            OrderManagerList = new List<OrderManager>();
        }
        #endregion
        #region order manager list
        private void AddOrderManager(OrderManager orderManager)
        {
            bool duplicateEntry = false;

            /// get the messenger around it
            orderManager.OnEventMessenger += new EventHandler<EventMessenger>(base_OnEventMessenger);


            for (int count = 0; count < OrderManagerList.Count; count++)
            {
                if (OrderManagerList[count].OrderEntry.OrderId == orderManager.OrderEntry.OrderId)
                {
                    OrderManagerList[count].AbortAllThreads();
                    OrderManagerList[count] = orderManager;
                    duplicateEntry = true;
                    break;
                }
            }

            if (!duplicateEntry)
            {
                OrderManagerList.Add(orderManager);
            }
        }
        #endregion
        #region fetch
        /// <summary>
        /// Gets all the others for this site
        /// </summary>
        /// <returns></returns>
        private void FetchOrdersThread()
        {
            SendMessage(MessageTypeOption.Message, "Fetching orders for Site " + SiteEntry.SiteName + " from database");

            ClearOrderManagerList();

            List<Order> orderList = _dataRepositoryManager.FetchOrders(SiteEntry.SiteId);

            foreach( Order order in orderList)
            {
                AddOrderManager(new OrderManager(SiteEntry, order));
            }

            /// we are done, send the message that we are done.
            SendMessage(MessageTypeOption.FetchOrdersThread, SiteEntry.SiteId.ToString());
        }
        /// <summary>
        /// This will fetch orders that has a 
        /// start date. Warning: NOT THREAD
        /// </summary>
        /// <param name="startDate"></param>
        private List<OrderManager> FetchOrders(DateTime startDate)
        {
            List<OrderManager> orderManagerList = new List<OrderManager>();

            List<Order> orderList = _dataRepositoryManager.FetchOrders(SiteEntry.SiteId, startDate);

            foreach (Order order in orderList)
            {
                OrderManager orderManager = new OrderManager(SiteEntry, order);
                orderManager.OnEventMessenger += new EventHandler<EventMessenger>(base_OnEventMessenger);
                
                orderManagerList.Add(orderManager);
            }

            return orderManagerList;
        }
        #endregion
        #region clear
        /// <summary>
        /// Stops anything that is happening with order manager items and
        /// clear the list out
        /// </summary>
        public void ClearOrderManagerList()
        {
            /// first we stop everything from all orders
            foreach (OrderManager orderManager in OrderManagerList)
            {
                orderManager.AbortAllThreads();
            }

            /// now we clear the list
            OrderManagerList.Clear();
        }
        #endregion
        #endregion


        #region public methods
        #region xml
        /// <summary>
        /// This parses the order list xml
        /// </summary>
        /// <param name="xOrderList"></param>
        public override void ParseXml(XElement xOrderList)
        {
            if (xOrderList.Name.ToString() == XmlNameOption.OrderList.ToString())
            {
                /// parse and save each order
                foreach (XElement xOrder in xOrderList.Elements())
                {
                    _dataRepositoryManager.SaveOrder(SiteEntry.SiteId, xOrder);
                }
            }
        }
        #endregion
        #region download
        /// <summary>
        /// Gets the data from the website and store it in the database
        /// </summary>
        /// <param name="dateTimeFrom"></param>
        private void DownloadOrderListThread(object startDateTimeObject)
        {
            try
            {
                DateTime startDateTime = (DateTime)startDateTimeObject;

                if (_webAction != null)
                {
                    /// get the orders
                    if (_webAction.GetOrderList(startDateTime))
                    {
                        ZetaClientConfiguration zetaClientConfiguration = new ZetaClientConfiguration();
                        XElement xOrders = XElement.Parse(_webAction.Data);

                        SendMessage(MessageTypeOption.Message, "Saving Order Header List");

                        ParseXml(xOrders);

                        if (zetaClientConfiguration.DownloadOrderDetails)
                        {
                            List<OrderManager> orderManagerList = FetchOrders(startDateTime);

                            foreach (OrderManager orderManager in orderManagerList)
                            {
                                orderManager.OnEventMessenger += new EventHandler<EventMessenger>(base_OnEventMessenger);
                                orderManager.DownloadOrderDetails(false);
                            }
                        }
                    }

                    SendMessage(MessageTypeOption.Message, "Fetching Order Header List from database");

                    /// now get information from the 
                    /// database
                    FetchOrdersThread();

                    SendMessage(MessageTypeOption.DownloadOrderListThread, SiteEntry.SiteId.ToString());

                    SendMessage(MessageTypeOption.Message, "Order Header List download completed.");
                }
            }
            catch (ThreadAbortException)
            {
                SendMessage(MessageTypeOption.Message, "Order Download aborted");
            }
        }
        #endregion
        #region order
        /// <summary>
        /// Gets a OrderManager contained inside here
        /// </summary>
        /// <param name="orderId"></param>
        /// <returns></returns>
        public OrderManager GetOrderManager(Guid orderId)
        {
            OrderManager orderManager = null;


            var orderManagerData = (from orderManagerItem in OrderManagerList
                                    where orderManagerItem.OrderEntry.OrderId == orderId
                                    select orderManagerItem).Take(1);

            if (orderManagerData.Count() > 0)
            {
                orderManager = orderManagerData.First();
            }

            return orderManager;
        }
        /// <summary>
        /// Fetches from the database all the orders from this 
        /// entry. When done message for FetchOrderThread will be 
        /// sent with the SiteId on it.
        /// </summary>
        public void FetchOrders()
        {
            Thread thread = new Thread(new ThreadStart(FetchOrdersThread));

            ThreadManager.AddThread(OrderIdGuid, ThreadActionOption.FetchOrders, thread);
        }
        /// <summary>
        /// Download only orders which have higher date than
        /// the newest one found on the database.
        /// </summary>
        public void DownloadOrders()
        {
            Thread thread = new Thread(new ParameterizedThreadStart(DownloadOrderListThread));

            ThreadManager.AddThread(OrderIdGuid, ThreadActionOption.DownloadOrders, thread, LatestOrderDateTime);
        }
        /// <summary>
        /// Gets orders from the website based on a datetime
        /// </summary>
        public void DownloadOrders(DateTime startDateTime)
        {
            Thread thread = new Thread(new ParameterizedThreadStart(DownloadOrderListThread));

            ThreadManager.AddThread(OrderIdGuid, ThreadActionOption.DownloadOrders, thread, startDateTime);
        }
        #endregion
        /// <summary>
        /// Removes this site from existense
        /// </summary>
        /// <returns></returns>
        public void DeleteSite()
        {
            /// First stop all threads under this guy.
            AbortAllThreads();

            /// take out all of the connection to the 
            /// list of orders
            OrderManagerList.Clear();

            /// delete the site and all the records under it.
            _dataRepositoryManager.DeleteSite(SiteEntry);
        }
        #endregion
    }
}
